package com.cencat.common.config;

import com.cencat.common.constants.CommonConstants;
import com.cencat.common.enums.ErrorCode;
import com.cencat.common.exception.BusinessException;
import com.cencat.common.utils.CencatStringUtils;
import com.cencat.common.utils.TenantUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * 多租户拦截器
 * 自动从请求头中提取租户ID并设置到上下文中
 * 
 * @author cencat
 * @since 2024-01-01
 */
@Component

public class TenantInterceptor implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(TenantInterceptor.class);

    /**
     * 租户ID请求头名称
     */
    private static final String TENANT_HEADER = "X-Tenant-Id";
    
    /**
     * 租户ID请求参数名称
     */
    private static final String TENANT_PARAM = "tenantId";

    /**
     * 不需要租户验证的路径
     */
    private static final String[] EXCLUDE_PATHS = {
        "/api/auth/login",
        "/api/auth/register",
        "/api/auth/refresh",
        "/api/public",
        "/swagger-ui",
        "/v3/api-docs",
        "/actuator",
        "/error",
        "/favicon.ico"
    };

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestUri = request.getRequestURI();
        String method = request.getMethod();
        
        log.debug("多租户拦截器处理请求: {} {}", method, requestUri);
        
        // 检查是否需要跳过租户验证
        if (shouldSkipTenantValidation(requestUri)) {
            log.debug("跳过租户验证: {}", requestUri);
            return true;
        }
        
        // 提取租户ID
        String tenantId = extractTenantId(request);
        
        // 验证租户ID
        if (CencatStringUtils.isBlank(tenantId)) {
            log.warn("请求缺少租户ID: {} {}", method, requestUri);
            throw new BusinessException(ErrorCode.TENANT_NOT_FOUND, "请求头中缺少租户ID");
        }
        
        // 验证租户ID格式
        if (!isValidTenantId(tenantId)) {
            log.warn("租户ID格式无效: {}, URI: {} {}", tenantId, method, requestUri);
            throw new BusinessException(ErrorCode.TENANT_INVALID, "租户ID格式无效");
        }
        
        // 设置租户上下文
        try {
            TenantUtils.setCurrentTenantId(Long.parseLong(tenantId));
            log.debug("设置租户上下文成功: {}", tenantId);
            
            // 验证租户是否有效
            if (!TenantUtils.isValidTenant(tenantId)) {
                log.warn("租户无效或已禁用: {}", tenantId);
             throw new BusinessException(ErrorCode.TENANT_DISABLED, "租户无效或已禁用");
            }
            
            return true;
        } catch (BusinessException e) {
            // 清理租户上下文
            TenantUtils.clearCurrentTenantId();
            throw e;
        } catch (Exception e) {
            log.error("设置租户上下文失败: tenantId={}, error={}", tenantId, e.getMessage(), e);
            TenantUtils.clearCurrentTenantId();
            throw new BusinessException(ErrorCode.INTERNAL_SERVER_ERROR, "租户上下文设置失败");
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 可以在这里添加一些后处理逻辑
        String tenantId = String.valueOf(TenantUtils.getCurrentTenantId());
        if (CencatStringUtils.isNotBlank(tenantId)) {
            // 在响应头中添加租户ID（可选）
            response.setHeader(TENANT_HEADER, tenantId);
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 清理租户上下文
        Long tenantId = TenantUtils.getCurrentTenantId();
        if (tenantId != null && tenantId > 0) {
            log.debug("清理租户上下文: {}", tenantId);
        }
        TenantUtils.clearCurrentTenantId();
        
        // 记录异常信息
        if (ex != null) {
            log.error("请求处理异常: {} {}, tenantId={}, error={}", 
                request.getMethod(), request.getRequestURI(), tenantId, ex.getMessage(), ex);
        }
    }

    /**
     * 提取租户ID
     * 优先级：请求头 > 请求参数
     * 
     * @param request HTTP请求
     * @return 租户ID
     */
    private String extractTenantId(HttpServletRequest request) {
        // 1. 从请求头获取
        String tenantId = request.getHeader(TENANT_HEADER);
        if (CencatStringUtils.isNotBlank(tenantId)) {
            return tenantId.trim();
        }
        
        // 2. 从请求参数获取
        tenantId = request.getParameter(TENANT_PARAM);
        if (CencatStringUtils.isNotBlank(tenantId)) {
            return tenantId.trim();
        }
        
        // 3. 从JWT Token中获取（如果有的话）
        tenantId = extractTenantFromToken(request);
        if (CencatStringUtils.isNotBlank(tenantId)) {
            return tenantId.trim();
        }
        
        return null;
    }

    /**
     * 从JWT Token中提取租户ID
     * 
     * @param request HTTP请求
     * @return 租户ID
     */
    private String extractTenantFromToken(HttpServletRequest request) {
        try {
            String authorization = request.getHeader("Authorization");
            if (CencatStringUtils.isBlank(authorization) || !authorization.startsWith("Bearer ")) {
                return null;
            }
            
            String token = authorization.substring(7);
            // 这里可以解析JWT Token获取租户ID
            // 暂时返回null，具体实现可以根据JWT工具类来完成
            return null;
        } catch (Exception e) {
            log.debug("从Token中提取租户ID失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 检查是否应该跳过租户验证
     * 
     * @param requestUri 请求URI
     * @return 是否跳过
     */
    private boolean shouldSkipTenantValidation(String requestUri) {
        if (CencatStringUtils.isBlank(requestUri)) {
            return false;
        }
        
        // 检查排除路径
        for (String excludePath : EXCLUDE_PATHS) {
            if (requestUri.startsWith(excludePath)) {
                return true;
            }
        }
        
        // 检查静态资源
        if (isStaticResource(requestUri)) {
            return true;
        }
        
        return false;
    }

    /**
     * 检查是否为静态资源
     * 
     * @param requestUri 请求URI
     * @return 是否为静态资源
     */
    private boolean isStaticResource(String requestUri) {
        String[] staticExtensions = {".css", ".js", ".png", ".jpg", ".jpeg", ".gif", ".ico", ".svg", ".woff", ".woff2", ".ttf", ".eot"};
        
        for (String extension : staticExtensions) {
            if (requestUri.endsWith(extension)) {
                return true;
            }
        }
        
        return false;
    }

    /**
     * 验证租户ID格式
     * 
     * @param tenantId 租户ID
     * @return 是否有效
     */
    private boolean isValidTenantId(String tenantId) {
        if (CencatStringUtils.isBlank(tenantId)) {
            return false;
        }
        
        // 租户ID长度检查
        if (tenantId.length() < 1 || tenantId.length() > 50) {
            return false;
        }
        
        // 租户ID格式检查（只允许字母、数字、下划线、中划线）
        return tenantId.matches("^[a-zA-Z0-9_-]+$");
    }

    /**
     * 获取当前租户ID（用于日志记录）
     * 
     * @return 租户ID
     */
    public static String getCurrentTenantId() {
        return String.valueOf(TenantUtils.getCurrentTenantId());
    }

    /**
     * 检查当前请求是否有租户上下文
     * 
     * @return 是否有租户上下文
     */
    public static boolean hasTenantContext() {
        Long tenantId = TenantUtils.getCurrentTenantId();
        return tenantId != null && tenantId > 0;
    }

    /**
     * 强制设置租户ID（谨慎使用）
     * 
     * @param tenantId 租户ID
     */
    public static void forceTenantId(String tenantId) {
        if (CencatStringUtils.isNotBlank(tenantId)) {
            TenantUtils.setCurrentTenantId(Long.parseLong(tenantId));
            log.debug("强制设置租户ID: {}", tenantId);
        }
    }

    /**
     * 临时切换租户（用于系统内部调用）
     * 
     * @param tenantId 目标租户ID
     * @param action 要执行的操作
     */
    public static void withTenant(String tenantId, Runnable action) {
        Long originalTenantId = TenantUtils.getCurrentTenantId();
        try {
            TenantUtils.setCurrentTenantId(Long.parseLong(tenantId));
            action.run();
        } finally {
            if (originalTenantId != null && originalTenantId > 0) {
                TenantUtils.setCurrentTenantId(originalTenantId);
            } else {
                TenantUtils.clearCurrentTenantId();
            }
        }
    }

    /**
     * 临时切换租户（用于系统内部调用，有返回值）
     * 
     * @param tenantId 目标租户ID
     * @param supplier 要执行的操作
     * @param <T> 返回值类型
     * @return 操作结果
     */
    public static <T> T withTenant(String tenantId, java.util.function.Supplier<T> supplier) {
        Long originalTenantId = TenantUtils.getCurrentTenantId();
        try {
            TenantUtils.setCurrentTenantId(Long.parseLong(tenantId));
            return supplier.get();
        } finally {
            if (originalTenantId != null && originalTenantId > 0) {
                TenantUtils.setCurrentTenantId(originalTenantId);
            } else {
                TenantUtils.clearCurrentTenantId();
            }
        }
    }
}